package web.suzy.oj.manager.admin.system;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.system.oshi.OshiUtil;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import web.suzy.oj.common.exception.StatusFailException;
import web.suzy.oj.config.NacosSwitchConfig;
import web.suzy.oj.config.SwitchConfig;
import web.suzy.oj.config.WebConfig;
import web.suzy.oj.dao.common.FileEntityService;
import web.suzy.oj.manager.email.EmailManager;
import web.suzy.oj.pojo.dto.*;
import web.suzy.oj.pojo.entity.common.File;
import web.suzy.oj.pojo.vo.ConfigVO;
import web.suzy.oj.utils.ConfigUtils;

import java.util.List;
import java.util.Properties;

/**
 * YangSuzy 软件工作室
 * 类名: ConfigManager
 * 描述: ---- 待定 -----
 * 功能: 动态修改网站配置，获取后台服务状态及判题服务器的状态
 * ============未完成================
 * 1.获取评测机服务信息
 *
 * @author YangSuzy
 * Date: 2022/11/17 18:13
 */
@Component
@Slf4j(topic = "suzyoj")
public class ConfigManager {
    @Autowired
    private ConfigVO configVo;

    @Autowired
    private EmailManager emailManager;

    @Autowired
    private FileEntityService fileEntityService;

    @Autowired
    private ConfigUtils configUtils;

    @Autowired
    private NacosSwitchConfig nacosSwitchConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Value("${spring.application.name}")
    private String currentServiceName;

    @Value("${spring.cloud.nacos.url}")
    private String NACOS_URL;

    @Value("${spring.cloud.nacos.config.prefix}")
    private String prefix;

    @Value("${spring.profiles.active}")
    private String active;

    @Value("${spring.cloud.nacos.config.file-extension}")
    private String fileExtension;

    @Value("${spring.cloud.nacos.config.group}")
    private String GROUP;

    @Value("${spring.cloud.nacos.config.type}")
    private String TYPE;

    @Value("${spring.cloud.nacos.config.username}")
    private String nacosUsername;

    @Value("${spring.cloud.nacos.config.password}")
    private String nacosPassword;

    /**
     * 方法名: sendNewConfigToNacos
     * 描述: 向 nacos注册中心发送新配置
     *
     * @return boolean
     * @date 2022/11/17 18:23
     * @auther YangSuzy
     **/
    public boolean sendNewConfigToNacos() {
        //设置nacos配置信息
        Properties properties = new Properties();
        properties.put("serverAddr", NACOS_URL);
        properties.put("username", nacosUsername);
        properties.put("password", nacosPassword);

        com.alibaba.nacos.api.config.ConfigService configService = null;
        boolean isOK = false;
        try {
            //创建配置
            configService = NacosFactory.createConfigService(properties);
            //发布配置：suzyoj-dev.yml
            isOK = configService.publishConfig(
                    prefix + "-" + active + "." + fileExtension,
                    GROUP,
                    configUtils.getConfigContent(),
                    TYPE);
        } catch (NacosException e) {
            log.error("通过nacos修改网站配置异常--------------->{}", e.getMessage());
        }
        return isOK;
    }

    /**
     * 方法名: getServiceInfo
     * 描述: 获取当前服务的相关信息，获取当前系统的cpu情况，内存使用情况
     *
     * @return cn.hutool.json.JSONObject
     * @date 2022/11/29 14:08
     * @auther YangSuzy
     **/
    public JSONObject getServiceInfo() {

        JSONObject result = new JSONObject();

        //获取后台在nacos上注册的服务实例
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances(currentServiceName);

        //获取nacos中心配置所在的机器环境
        String response = restTemplate.getForObject(NACOS_URL + "/nacos/v1/ns/operator/metrics", String.class);

        JSONObject jsonObject = JSONUtil.parseObj(response);

        //获取当前数据后台所在机器环境

        //当前机器的cpu核数
        int cores = OshiUtil.getCpuInfo().getCpuNum();
        //当前服务所在机器cpu使用率
        double cpuLoad = 100 - OshiUtil.getCpuInfo().getFree();
        String percentCpuLoad = String.format("%.2f", cpuLoad) + "%";
        //当前服务所在机器总内存
        double totalVirtualMemory = OshiUtil.getMemory().getTotal();
        //当前服务所在机器空闲内存
        double freePhysicalMemorySize = OshiUtil.getMemory().getAvailable();
        double value = freePhysicalMemorySize / totalVirtualMemory;
        //当前服务所在机器内存使用率
        String percentMemoryLoad = String.format("%.2f", (1 - value) * 100) + "%";

        //保存环境数据
        result.put("nacos", jsonObject);
        result.put("backupCores", cores);
        result.put("backupService", serviceInstances);
        result.put("backupPercentCpuLoad", percentCpuLoad);
        result.put("backupPercentMemoryLoad", percentMemoryLoad);
        return result;
    }

    /**
     * 方法名: getWebConfig
     * 描述: 获取网站基本配置信息
     *
     * @return web.suzy.oj.pojo.dto.WebConfigDTO
     * @date 2022/11/29 14:35
     * @auther YangSuzy
     **/
    public WebConfigDTO getWebConfig() {
        //从nacos中获取网站基本配置
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        return WebConfigDTO.builder()
                .baseUrl(UnicodeUtil.toString(webConfig.getBaseUrl()))
                .name(UnicodeUtil.toString(webConfig.getName()))
                .shortName(UnicodeUtil.toString(webConfig.getShortName()))
                .description(UnicodeUtil.toString(webConfig.getDescription()))
                .register(webConfig.getRegister())
                .recordName(UnicodeUtil.toString(webConfig.getRecordName()))
                .recordUrl(UnicodeUtil.toString(webConfig.getRecordUrl()))
                .projectName(UnicodeUtil.toString(webConfig.getProjectName()))
                .projectUrl(UnicodeUtil.toString(webConfig.getProjectUrl()))
                .build();
    }

    /**
     * 方法名: setWebConfig
     * 描述: 设置网站基本配置信息
     *
     * @param config 配置信息
     * @return void
     * @date 2022/11/29 14:56
     * @auther YangSuzy
     **/
    public void setWebConfig(WebConfigDTO config) throws StatusFailException {

        WebConfig webConfig = nacosSwitchConfig.getWebConfig();

        if (!StringUtils.isEmpty(config.getBaseUrl())) {
            webConfig.setBaseUrl(config.getBaseUrl());
        }
        if (!StringUtils.isEmpty(config.getName())) {
            webConfig.setName(config.getName());
        }
        if (!StringUtils.isEmpty(config.getShortName())) {
            webConfig.setShortName(config.getShortName());
        }
        if (!StringUtils.isEmpty(config.getDescription())) {
            webConfig.setDescription(config.getDescription());
        }
        if (config.getRegister() != null) {
            webConfig.setRegister(config.getRegister());
        }
        if (!StringUtils.isEmpty(config.getRecordName())) {
            webConfig.setRecordName(config.getRecordName());
        }
        if (!StringUtils.isEmpty(config.getRecordUrl())) {
            webConfig.setRecordUrl(config.getRecordUrl());
        }
        if (!StringUtils.isEmpty(config.getProjectName())) {
            webConfig.setProjectName(config.getProjectName());
        }
        if (!StringUtils.isEmpty(config.getProjectUrl())) {
            webConfig.setProjectUrl(config.getProjectUrl());
        }
        boolean isOk = nacosSwitchConfig.publishWebConfig();
        if (!isOk) {
            throw new StatusFailException("修改失败");
        }
    }

    /**
     * 方法名: getEmailConfig
     * 描述: 获取邮箱配置信息
     *
     * @return web.suzy.oj.pojo.dto.EmailConfigDTO
     * @date 2022/11/29 15:00
     * @auther YangSuzy
     **/
    public EmailConfigDTO getEmailConfig() {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        return EmailConfigDTO.builder()
                .emailUsername(webConfig.getEmailUsername())
                .emailPassword(webConfig.getEmailPassword())
                .emailHost(webConfig.getEmailHost())
                .emailPort(webConfig.getEmailPort())
                .emailSsl(webConfig.getEmailSsl())
                .build();
    }

    /**
     * 方法名: setEmailConfig
     * 描述: 设置邮箱配置信息
     *
     * @param config 配置信息
     * @return void
     * @date 2022/11/29 15:04
     * @auther YangSuzy
     **/
    public void setEmailConfig(EmailConfigDTO config) throws StatusFailException {
        WebConfig webConfig = nacosSwitchConfig.getWebConfig();
        if (!StringUtils.isEmpty(config.getEmailHost())) {
            webConfig.setEmailHost(config.getEmailHost());
        }
        if (!StringUtils.isEmpty(config.getEmailPassword())) {
            webConfig.setEmailPassword(config.getEmailPassword());
        }
        if (config.getEmailPort() != null) {
            webConfig.setEmailPort(config.getEmailPort());
        }
        if (!StringUtils.isEmpty(config.getEmailUsername())) {
            webConfig.setEmailUsername(config.getEmailUsername());
        }
        if (config.getEmailSsl() != null) {
            webConfig.setEmailSsl(config.getEmailSsl());
        }

        boolean isOk = nacosSwitchConfig.publishWebConfig();
        if (!isOk) {
            throw new StatusFailException("修改失败");
        }
    }

    /**
     * 方法名: testEmail
     * 描述: 测试发送邮件功能
     *
     * @param testEmailDto 测试邮箱
     * @return void
     * @date 2022/11/29 15:09
     * @auther YangSuzy
     **/
    public void testEmail(TestEmailDTO testEmailDto) throws StatusFailException {
        String email = testEmailDto.getEmail();
        if (StringUtils.isEmpty(email)) {
            throw new StatusFailException("测试的邮箱不能为空！");
        }
        boolean isEmail = Validator.isEmail(email);
        if (isEmail) {
            emailManager.testEmail(email);
        } else {
            throw new StatusFailException("测试的邮箱格式不正确！");
        }
    }

    /**
     * 方法名: getDBAndRedisConfig
     * 描述: 获取数据库和 Redis的配置
     *
     * @return web.suzy.oj.pojo.dto.DBAndRedisConfigDTO
     * @date 2022/11/29 21:45
     * @auther YangSuzy
     **/
    public DBAndRedisConfigDTO getDBAndRedisConfig() {
        return DBAndRedisConfigDTO.builder()
                .dbName(configVo.getMysqlDBName())
                .dbHost(configVo.getMysqlHost())
                .dbPort(configVo.getMysqlPort())
                .dbUsername(configVo.getMysqlUsername())
                .dbPassword(configVo.getMysqlPassword())
                .redisHost(configVo.getRedisHost())
                .redisPort(configVo.getRedisPort())
                .redisPassword(configVo.getRedisPassword())
                .build();
    }

    /**
     * 方法名: setDBAndRedisConfig
     * 描述: 设置数据库和 Redis的配置
     *
     * @param config 配置信息
     * @return void
     * @date 2022/11/30 9:03
     * @auther YangSuzy
     **/
    public void setDBAndRedisConfig(DBAndRedisConfigDTO config) throws StatusFailException {

        //设置数据库配置
        if (!StringUtils.isEmpty(config.getDbName())) {
            configVo.setMysqlDBName(config.getDbName());
        }
        if (!StringUtils.isEmpty(config.getDbHost())) {
            configVo.setMysqlHost(config.getDbHost());
        }
        if (config.getDbPort() != null) {
            configVo.setMysqlPort(config.getDbPort());
        }
        if (!StringUtils.isEmpty(config.getDbUsername())) {
            configVo.setMysqlUsername(config.getDbUsername());
        }
        if (!StringUtils.isEmpty(config.getDbPassword())) {
            configVo.setMysqlPassword(config.getDbPassword());
        }

        //设置redis配置
        if (!StringUtils.isEmpty(config.getRedisHost())) {
            configVo.setRedisHost(config.getRedisHost());
        }
        if (config.getRedisPort() != null) {
            configVo.setRedisPort(config.getRedisPort());
        }
        if (!StringUtils.isEmpty(config.getRedisPassword())) {
            configVo.setRedisPassword(config.getRedisPassword());
        }

        boolean isOk = sendNewConfigToNacos();

        if (!isOk) {
            throw new StatusFailException("修改失败");
        }
    }

    /**
     * 方法名: getSwitchConfig
     * 描述: 获取功能开关配置信息
     *
     * @return SwitchConfigDTO
     * @date 2022/11/30 10:23
     * @auther YangSuzy
     **/
    public SwitchConfigDTO getSwitchConfig() {
        SwitchConfig switchConfig = nacosSwitchConfig.getSwitchConfig();
        SwitchConfigDTO switchConfigDTO = new SwitchConfigDTO();
        BeanUtil.copyProperties(switchConfig, switchConfigDTO);
        return switchConfigDTO;
    }

    /**
     * 方法名: setSwitchConfig
     * 描述: 设置功能开关配置
     *
     * @param config 配置信息
     * @return void
     * @date 2022/11/30 10:30
     * @auther YangSuzy
     **/
    public void setSwitchConfig(SwitchConfigDTO config) throws StatusFailException {

        SwitchConfig switchConfig = nacosSwitchConfig.getSwitchConfig();

        if (config.getOpenPublicDiscussion() != null) {
            switchConfig.setOpenPublicDiscussion(config.getOpenPublicDiscussion());
        }
        if (config.getOpenPublicJudge() != null) {
            switchConfig.setOpenPublicJudge(config.getOpenPublicJudge());
        }

        if (config.getDefaultCreateDiscussionACInitValue() != null) {
            switchConfig.setDefaultCreateDiscussionACInitValue(config.getDefaultCreateDiscussionACInitValue());
        }

        if (config.getDefaultCreateDiscussionDailyLimit() != null) {
            switchConfig.setDefaultCreateDiscussionDailyLimit(config.getDefaultCreateDiscussionDailyLimit());
        }

        if (config.getDefaultCreateCommentACInitValue() != null) {
            switchConfig.setDefaultCreateCommentACInitValue(config.getDefaultCreateCommentACInitValue());
        }

        if (config.getDefaultSubmitInterval() != null) {
            if (config.getDefaultSubmitInterval() >= 0) {
                switchConfig.setDefaultSubmitInterval(config.getDefaultSubmitInterval());
            } else {
                switchConfig.setDefaultSubmitInterval(0);
            }
        }

        boolean isOk = nacosSwitchConfig.publishSwitchConfig();
        if (!isOk) {
            throw new StatusFailException("修改失败");
        }
    }

    /**
     * 方法名: deleteHomeCarousel
     * 描述: 删除主页轮播图文件
     *
     * @param id 图片ID
     * @return void
     * @date 2022/11/30 10:37
     * @auther YangSuzy
     **/
    public void deleteHomeCarousel(Long id) throws StatusFailException {
        File imgFile = fileEntityService.getById(id);
        if (imgFile == null) {
            throw new StatusFailException("文件id错误，图片不存在");
        }
        boolean isOk = fileEntityService.removeById(id);
        if (isOk) {
            FileUtil.del(imgFile.getFilePath());
        } else {
            throw new StatusFailException("删除失败！");
        }
    }
}
